package com.carter.springframework.core.annotation;

import cn.hutool.core.lang.Assert;
import com.carter.springframework.beans.exception.BeanException;
import com.carter.springframework.util.ClassUtils;
import com.carter.springframework.util.ReflectionUtils;
import com.sun.istack.internal.Nullable;

import java.lang.annotation.Annotation;
import java.lang.reflect.Array;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Arrays;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

public class SynthesizedMergedAnnotationInvocationHandler<A extends Annotation> implements InvocationHandler {
    //合并注解实例
    private final MergedAnnotation<?> annotation;
    //代理注解的类型
    private final Class<A> type;
    //代理注解的注解方法
    private final AttributeMethods attributes;
    //注解属性的值缓存
    private final Map<String, Object> valueCache = new ConcurrentHashMap<>(8);

    @Nullable
    private volatile Integer hashCode;

    @Nullable
    private volatile String string;

    private SynthesizedMergedAnnotationInvocationHandler(MergedAnnotation<A> annotation, Class<A> type) {
        Assert.notNull(annotation, "MergedAnnotation must not be null");
        Assert.notNull(type, "Type must not be null");
        Assert.isTrue(type.isAnnotation(), "Type must be an annotation");
        this.annotation = annotation;
        this.type = type;
        this.attributes = AttributeMethods.forAnnotationType(type);
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        /**
        //代理equals方法
        if (ReflectionUtils.isEqualsMethod(method)){
            return annotationEquals(args[0]);
        }
        // 代理 hashCode 方法
        if (ReflectionUtils.isHashCodeMethod(method)) {
            return annotationHashCode();
        }
        // 代理 toString 方法
        if (ReflectionUtils.isToStringMethod(method)) {
            return annotationToString();
        }
        // 代理 isAnnotationTypeMethod 方法
        if (isAnnotationTypeMethod(method)) {
            return this.type;
        }*/
        // 代理获取注解属性的方法
        if (this.attributes.indexOf(method.getName()) != -1) {
            return getAttributeValue(method);
        }

        return null;
    }

    private Object getAttributeValue(Method method) {
        Object value = this.valueCache.computeIfAbsent(method.getName(), attributeName -> {
            //获取代理方法的返回值类型
            Class<?> type = ClassUtils.resolvePrimitiveIfNecessary(method.getReturnType());
            return this.annotation.getValue(attributeName, type).orElseThrow(() -> new BeanException("No value found for attribute named '" + attributeName +
                    "' in merged annotation " + this.annotation.getType().getName()));
        });
        if (value.getClass().isArray()&& Array.getLength(value)>0){
            //value = cloneArray(value);
        }
        return value;
    }

    static <A extends Annotation> A createProxy(MergedAnnotation<A> annotation, Class<A> type) {
        ClassLoader classLoader = type.getClassLoader();
        InvocationHandler handler = new SynthesizedMergedAnnotationInvocationHandler<>(annotation, type);
        Class<?>[] interfaces = isVisible(classLoader, SynthesizedAnnotation.class) ?
                new Class<?>[]{type, SynthesizedAnnotation.class} : new Class<?>[]{type};
        return (A) Proxy.newProxyInstance(classLoader, interfaces, handler);
    }

    private static boolean isVisible(ClassLoader classLoader, Class<?> interfaceClass) {
        if (classLoader == interfaceClass.getClassLoader()) {
            return true;
        }
        try {
            return Class.forName(interfaceClass.getName(), false, classLoader) == interfaceClass;
        } catch (ClassNotFoundException ex) {
            return false;
        }
    }
}
